package services

import (
	"fmt"
	"strings"
	"sync"
	"time"

	"game-simple/internal/framework/system/dto"
	"game-simple/internal/framework/system/models"

	"gorm.io/gorm"
)

// SequenceService 编号规则服务
type SequenceService struct {
	db *gorm.DB
	mu sync.Mutex // 用于生成编号时的并发控制
}

// NewSequenceService 创建编号规则服务（需要从外部传入 db）
// 注意：为了避免循环依赖，不直接导入 core 包
func NewSequenceService(db *gorm.DB) *SequenceService {
	if db == nil {
		panic("db cannot be nil")
	}
	return &SequenceService{
		db: db,
	}
}

// CreateRule 创建编号规则
func (s *SequenceService) CreateRule(req *dto.CreateSequenceRuleRequest) (*models.SequenceRule, error) {
	rule := &models.SequenceRule{
		Code:        req.Code,
		Name:        req.Name,
		Prefix:      req.Prefix,
		DateFormat:   req.DateFormat,
		SequenceLen:  req.SequenceLen,
		ResetType:    req.ResetType,
		Description:  req.Description,
		Status:       "active",
		CurrentSeq:   0,
	}

	if rule.DateFormat == "" {
		rule.DateFormat = "YYYYMMDD"
	}
	if rule.SequenceLen == 0 {
		rule.SequenceLen = 6
	}
	if rule.ResetType == "" {
		rule.ResetType = "never"
	}

	if err := s.db.Create(rule).Error; err != nil {
		return nil, err
	}

	return rule, nil
}

// UpdateRule 更新编号规则
func (s *SequenceService) UpdateRule(code string, req *dto.UpdateSequenceRuleRequest) (*models.SequenceRule, error) {
	rule := &models.SequenceRule{}
	if err := s.db.Where("code = ?", code).First(rule).Error; err != nil {
		return nil, err
	}

	if req.Name != "" {
		rule.Name = req.Name
	}
	if req.Prefix != "" {
		rule.Prefix = req.Prefix
	}
	if req.DateFormat != "" {
		rule.DateFormat = req.DateFormat
	}
	if req.SequenceLen > 0 {
		rule.SequenceLen = req.SequenceLen
	}
	if req.ResetType != "" {
		rule.ResetType = req.ResetType
	}
	if req.Status != "" {
		rule.Status = req.Status
	}
	if req.Description != "" {
		rule.Description = req.Description
	}

	if err := s.db.Save(rule).Error; err != nil {
		return nil, err
	}

	return rule, nil
}

// GetRule 获取编号规则
func (s *SequenceService) GetRule(code string) (*models.SequenceRule, error) {
	rule := &models.SequenceRule{}
	if err := s.db.Where("code = ?", code).First(rule).Error; err != nil {
		return nil, err
	}
	return rule, nil
}

// ListRules 列出所有编号规则
func (s *SequenceService) ListRules() ([]*models.SequenceRule, error) {
	var rules []*models.SequenceRule
	if err := s.db.Find(&rules).Error; err != nil {
		return nil, err
	}
	return rules, nil
}

// DeleteRule 删除编号规则
func (s *SequenceService) DeleteRule(code string) error {
	return s.db.Where("code = ?", code).Delete(&models.SequenceRule{}).Error
}

// GenerateSequence 生成编号（线程安全）
func (s *SequenceService) GenerateSequence(code string) (string, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	// 获取规则
	rule := &models.SequenceRule{}
	if err := s.db.Where("code = ? AND status = ?", code, "active").First(rule).Error; err != nil {
		return "", fmt.Errorf("编号规则不存在或已停用: %w", err)
	}

	now := time.Now()
	shouldReset := false

	// 检查是否需要重置序号
	if rule.ResetType != "never" && rule.LastDate != nil {
		switch rule.ResetType {
		case "daily":
			shouldReset = !isSameDay(*rule.LastDate, now)
		case "monthly":
			shouldReset = !isSameMonth(*rule.LastDate, now)
		case "yearly":
			shouldReset = !isSameYear(*rule.LastDate, now)
		}
	} else if rule.LastDate == nil {
		// 首次生成
		shouldReset = false
	}

	// 重置序号或递增
	if shouldReset {
		rule.CurrentSeq = 1
	} else {
		rule.CurrentSeq++
	}

	rule.LastDate = &now

	// 更新数据库
	if err := s.db.Save(rule).Error; err != nil {
		return "", err
	}

	// 生成编号
	sequence := s.buildSequence(rule, now)

	return sequence, nil
}

// buildSequence 构建编号字符串
func (s *SequenceService) buildSequence(rule *models.SequenceRule, t time.Time) string {
	var parts []string

	// 添加前缀
	if rule.Prefix != "" {
		parts = append(parts, rule.Prefix)
	}

	// 添加日期部分
	if rule.DateFormat != "" {
		dateStr := s.formatDate(t, rule.DateFormat)
		if dateStr != "" {
			parts = append(parts, dateStr)
		}
	}

	// 添加序号部分
	seqStr := fmt.Sprintf("%0*d", rule.SequenceLen, rule.CurrentSeq)
	parts = append(parts, seqStr)

	return strings.Join(parts, "")
}

// formatDate 格式化日期
func (s *SequenceService) formatDate(t time.Time, format string) string {
	format = strings.ReplaceAll(format, "YYYY", t.Format("2006"))
	format = strings.ReplaceAll(format, "MM", t.Format("01"))
	format = strings.ReplaceAll(format, "DD", t.Format("02"))
	format = strings.ReplaceAll(format, "HH", t.Format("15"))
	format = strings.ReplaceAll(format, "mm", t.Format("04"))
	format = strings.ReplaceAll(format, "ss", t.Format("05"))
	return format
}

// isSameDay 判断是否同一天
func isSameDay(t1, t2 time.Time) bool {
	return t1.Year() == t2.Year() &&
		t1.Month() == t2.Month() &&
		t1.Day() == t2.Day()
}

// isSameMonth 判断是否同一月
func isSameMonth(t1, t2 time.Time) bool {
	return t1.Year() == t2.Year() &&
		t1.Month() == t2.Month()
}

// isSameYear 判断是否同一年
func isSameYear(t1, t2 time.Time) bool {
	return t1.Year() == t2.Year()
}

// GetCurrentSequence 获取当前序号（不递增）
func (s *SequenceService) GetCurrentSequence(code string) (int, error) {
	rule := &models.SequenceRule{}
	if err := s.db.Where("code = ?", code).First(rule).Error; err != nil {
		return 0, err
	}
	return rule.CurrentSeq, nil
}

// ResetSequence 重置序号
func (s *SequenceService) ResetSequence(code string) error {
	rule := &models.SequenceRule{}
	if err := s.db.Where("code = ?", code).First(rule).Error; err != nil {
		return err
	}

	rule.CurrentSeq = 0
	rule.LastDate = nil

	return s.db.Save(rule).Error
}

